package com.ruoyi.client.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.stream.CollectorUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.client.constants.ListConstants;
import com.ruoyi.client.domain.entity.*;
import com.ruoyi.client.domain.page.ClientPageParam;
import com.ruoyi.client.domain.vo.CHArticleVo;
import com.ruoyi.client.domain.vo.EchartsVo;
import com.ruoyi.client.mapper.BlogArticleMapper;
import com.ruoyi.client.service.*;
import com.ruoyi.common.mybatis.core.page.PageQuery;
import com.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 文章表 服务实现类
 * </p>
 *
 * @author fz
 * @since 2025-02-27
 */
@Service
public class BlogArticleServiceImpl extends ServiceImpl<BlogArticleMapper, BlogArticle> implements IBlogArticleService {

    @Autowired
    BlogArticleMapper articleMapper;
    @Autowired
    IBlogLikeService likeService;
    @Autowired
    IBlogCollectService collectService;
    @Autowired
    IBlogTagsService tagsService;
    @Autowired
    IBlogUserService userService;
    @Autowired
    IBlogAttentionService attentionService;
    @Override
    public TableDataInfo<BlogArticle> getArticleByCategoryType(PageQuery pageQuery) {
        Page<BlogArticle> page = this.page(pageQuery.build(),buildWrapper(pageQuery.getParams()));
        Set<Long> userIds = page.getRecords().stream().map(v -> v.getUserId()).collect(Collectors.toSet());
        List<BlogUser> userList = userService.list(Wrappers.<BlogUser>lambdaQuery().in(CollectionUtil.isNotEmpty(userIds),BlogUser::getId, userIds));
        Map<Long, String> map = userList.stream().collect(Collectors.toMap(BlogUser::getId, BlogUser::getNickname));
        page.getRecords().forEach(v -> {
            String userName = map.get(v.getUserId());
            v.setUserName(userName);
        });
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<BlogArticle> getArticleAll(PageQuery pageQuery, BlogArticle article) {
        // 查看是否有listType
        TableDataInfo<BlogArticle> buildParams = null;
        if (CollectionUtil.isNotEmpty(pageQuery.getParams()) && ListConstants.LIST_ATTENTION.equals(pageQuery.getParams().get("listType"))){
            buildParams = buildParams(pageQuery);
            if (CollectionUtil.isEmpty(buildParams.getRows())) {
                return buildParams;
            }
            // 设置标签名
            setTagName(buildParams.getRows());
        }
        // 查看是否关注点赞
        Long userId = Long.valueOf((String) StpUtil.getLoginId());

        if (buildParams == null){
            Page<BlogArticle> page = this.page(pageQuery.build(),buildWrapper1(article));
            if (CollectionUtil.isEmpty(page.getRecords())) return TableDataInfo.build(page);
            likeAndCollection(userId,page.getRecords());
            // 设置标签名
            setTagName(page.getRecords());
            return TableDataInfo.build(page);
        }
        else {
            likeAndCollection(userId,buildParams.getRows());
            return buildParams;
        }

    }
    private void setTagName(List<BlogArticle> list) {
        Set<Long> tagIds = list.stream().map(v -> v.getTagId()).collect(Collectors.toSet());
        List<BlogTags> tagsList = tagsService.list(Wrappers.<BlogTags>lambdaQuery().in(BlogTags::getId, tagIds));
        Map<Long, List<BlogTags>> tagsMap = tagsList.stream().collect(Collectors.groupingBy(BlogTags::getId));
        list.forEach(v -> {
            List<BlogTags> tags = tagsMap.get(v.getTagId());
            v.setTagName(tags.get(0).getName());
        });
    }

    @Override
    public TableDataInfo<CHArticleVo> getHistroryPage(Long userId, ClientPageParam<CHArticleVo> pageParam) {
        Page<CHArticleVo> page = articleMapper.getHistoryPage(userId,pageParam.buildPage());
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<CHArticleVo> getCollectPage(Long userId, ClientPageParam<CHArticleVo> pageParam) {
        Page<CHArticleVo> page = articleMapper.getCollectPage(userId,pageParam.buildPage());
        return TableDataInfo.build(page);
    }

    @Override
    public TableDataInfo<BlogArticle> getDraftPage(Long userId,ClientPageParam<BlogArticle> pageParam) {
        List<BlogArticle> list = list(pageParam.buildPage(), Wrappers.<BlogArticle>lambdaQuery()
            .eq(BlogArticle::getUserId, userId)
            .eq(BlogArticle::getStatus, 1)
        );
        return TableDataInfo.build(list);
    }

    @Override
    public TableDataInfo<BlogArticle> getPublishPage(Long userId, ClientPageParam<BlogArticle> pageParam) {
        List<BlogArticle> list = list(pageParam.buildPage(), Wrappers.<BlogArticle>lambdaQuery()
            .eq(BlogArticle::getUserId, userId)
            .eq(BlogArticle::getStatus, 4)
        );
        return TableDataInfo.build(list);
    }

    private void likeAndCollection(Long userId, @NotNull List<BlogArticle> records) {
        Set<Long> likeSet = likeService.list(Wrappers.<BlogLike>lambdaQuery()
                .eq(BlogLike::getTargetType, 1)
                .eq(BlogLike::getUserId, userId))
            .stream()
            .map(v -> v.getTargetId()).collect(Collectors.toSet());
        Set<Long> collectSet = collectService.list(Wrappers.<BlogCollect>lambdaQuery()
                .eq(BlogCollect::getTargetType,1)
                .eq(BlogCollect::getUserId, userId))
            .stream().map(v -> v.getTargetId())
            .collect(Collectors.toSet());

        records.forEach(v -> {
            if (likeSet.contains(v.getId())) {
                v.setIsLike(true);
            }  else {
               v.setIsLike(false);
            }
            if (collectSet.contains(v.getId())) {
                v.setIsCollect(true);
            } else {
                v.setIsCollect(false);
            }
        });
    }

    private TableDataInfo<BlogArticle> buildParams(PageQuery pageQuery) {
        if (CollectionUtil.isEmpty(pageQuery.getParams())) {
            return null;
        }
        Map<String, Object> params = pageQuery.getParams();
//        String listType = (String) params.get("listType");
//        if ("ATTENTION".equals(listType)) {
//            // 获取关注列表
//            List<BlogAttention> attentionList = attentionService.list(Wrappers.<BlogAttention>lambdaQuery().eq(BlogAttention::getUserId, Long.valueOf((String) StpUtil.getLoginId())));
//            List<Long> targetUserIds = null;
//            if (CollectionUtil.isNotEmpty(attentionList)) {
//                targetUserIds = attentionList.stream().map(v -> v.getTargetUserId()).collect(Collectors.toList());
//
//            }
//        }
        Page<BlogArticle> attentionArticle = articleMapper.getAttentionArticle(Long.valueOf((String)StpUtil.getLoginId()), pageQuery.build());
        return TableDataInfo.build(attentionArticle);
    }

    private Wrapper buildWrapper1(BlogArticle article) {
        QueryWrapper<BlogArticle> queryWrapper = Wrappers.query();
        for (Field field : article.getClass().getDeclaredFields()) {
            try {
                field.setAccessible(true);
                Object value = field.get(article);
                if (value != null){
                    String name = convertString(field.getName());
                    if (field.getName().equals("title")){
                        queryWrapper.like(name,value);
                    }
                    else {
                        queryWrapper.eq(name, value);
                    }
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        queryWrapper.eq("status",4);
        queryWrapper.eq("is_public",1);
        queryWrapper.orderBy(true,false,"create_time");
        return queryWrapper;
    }

    /**
     * 将javabean字段转换为数据库的字段
     * @param input
     * @return
     */
    public  String convertString(String input) {
        if (input == null || input.isEmpty()) {
            return input; // 如果输入为空，直接返回
        }

        StringBuilder result = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            char currentChar = input.charAt(i);

            // 判断是否为大写字母
            if (Character.isUpperCase(currentChar)) {
                result.append('_'); // 在大写字母前添加下划线
                result.append(Character.toLowerCase(currentChar)); // 转换为小写
            } else {
                result.append(currentChar); // 非大写字母直接追加
            }
        }

        return result.toString();
    }
    private Wrapper<BlogArticle> buildWrapper(Map<String, Object> params) {
        QueryWrapper<BlogArticle> wrapper = new QueryWrapper<>();
        if (CollectionUtils.isEmpty(params)) return wrapper;

        Set<Map.Entry<String, Object>> set = params.entrySet();
        for (Map.Entry<String, Object> entry : set) {
            String field = entry.getKey();
            Object value = entry.getValue();

            if (value != null) {
                // 添加等值条件
                if (field.equals("categoryType")) {
                    wrapper.eq(field,value);
                }else {
                    wrapper.like(field,value);

                }
            }
        }
        return wrapper;
    }
    @Override
    public List<EchartsVo> addLikeNum(Long userId, LocalDateTime startTime, LocalDateTime endTime) {
        // 查询点赞记录
        List<BlogArticle> list = list(Wrappers.<BlogArticle>lambdaQuery()
            .eq(BlogArticle::getUserId, userId)
            .between(BlogArticle::getCreateTime, startTime, endTime)
        );
        // 如果查询结果为空，直接返回空列表
        if (CollectionUtil.isEmpty(list)) {
            return generateEmptyResult(startTime.toLocalDate(), endTime.toLocalDate());
        }
        // 按日期分组统计点赞数
        Map<LocalDate, Long> detail = list.stream()
            .collect(Collectors.groupingBy(
                blogLike -> blogLike.getCreateTime().toLocalDate(),
                Collectors.counting()
            ));
        // 补全没有值的日期
        return generateResultWithMissingDates(detail, startTime.toLocalDate(), endTime.toLocalDate());
    }
    /**
     * 生成时间范围内的所有日期
     */
    private List<LocalDate> generateDateRange(LocalDate startDate, LocalDate endDate) {
        long numOfDays = ChronoUnit.DAYS.between(startDate, endDate) + 1; // 包括结束日期
        return Stream.iterate(startDate, date -> date.plusDays(1))
            .limit(numOfDays)
            .collect(Collectors.toList());
    }

    /**
     * 生成补全后的结果
     */
    private List<EchartsVo> generateResultWithMissingDates(Map<LocalDate, Long> detail, LocalDate startDate, LocalDate endDate) {
        List<EchartsVo> result = new ArrayList<>();
        List<LocalDate> dateRange = generateDateRange(startDate, endDate);

        for (LocalDate date : dateRange) {
            EchartsVo vo = new EchartsVo();
            vo.setName(date.getMonthValue() + "月" + date.getDayOfMonth() + "日");
            vo.setValue(detail.getOrDefault(date, 0L)); // 如果有值则使用，否则补全为0
            result.add(vo);
        }

        return result;
    }

    /**
     * 生成空结果（所有日期的点赞数为0）
     */
    private List<EchartsVo> generateEmptyResult(LocalDate startDate, LocalDate endDate) {
        List<EchartsVo> result = new ArrayList<>();
        List<LocalDate> dateRange = generateDateRange(startDate, endDate);

        for (LocalDate date : dateRange) {
            EchartsVo vo = new EchartsVo();
            vo.setName(date.getMonthValue() + "月" + date.getDayOfMonth() + "日");
            vo.setValue(0L); // 点赞数为0
            result.add(vo);
        }

        return result;
    }
}
